import type { CreateOptions, Fn, Nullable } from '@/index'
import type { AxiosInstance, CancelTokenSource } from 'axios'
import { getAxiosInstance, getAxiosCancelTokenSource } from '@/http'
import { clone } from '@/utils'

/**
 * @file 真正执行的 api 流程
 */
class Task {
  isPending = false
  startTime = 0
  setTimeoutId: Nullable<number> = null
  pollCount = -1
  pollInterval = 5
  isStop = false
  options: Partial<CreateOptions> = {}
  cancelTokenSource: Nullable<CancelTokenSource> = null
  axiosInstance: Nullable<AxiosInstance> = null
  constructor(public fn: Fn, opt: CreateOptions) {
    this.options = clone(opt)
    const {
      pollCount = -1,
      pollInterval = 5,
      axiosInstance,
      requestConfig
    } = this.options
    this.pollCount = pollCount
    this.pollInterval = pollInterval
    this.isStop = this.pollCount === 0 ? true : false
    this.cancelTokenSource =
      requestConfig?.cancelTokenSource || getAxiosCancelTokenSource()
    this.options!.requestConfig!.cancelToken = this.cancelTokenSource?.token
    this.axiosInstance = axiosInstance || getAxiosInstance()
    const { delay = 0 } = this.options
    if (delay > 0) {
      setTimeout(this.bootstrap, delay * 1000)
    } else {
      this.bootstrap()
    }
  }
  stopPollApi = () => {
    this.isStop = true
    this.interruptRequest()
  }
  interruptRequest = () => {
    // 中断正在进行的请求
    this.isPending = false
    clearTimeout(this.setTimeoutId!)
    if (this.cancelTokenSource) {
      this.cancelTokenSource.cancel()
    }
  }
  isContinue = () => {
    if (this.pollCount === 0) {
      return false
    }
    if(this.isStop) {
      return false
    }
    return true
  }
  bootstrap = async () => {
    if (!this.isContinue()) {
      return
    }
    this.isPending = true
    this.startTime = new Date().getTime()
    try {
      const { requestConfig } = this.options
      const res = await this.axiosInstance?.(requestConfig!)
      this.fn(null, res)
    } catch (error) {
      this.fn(error)
    } finally {
      this.isPending = false
      if (this.isContinue()) {
        if (this.pollCount > 0) {
          this.pollCount -= 1
        }
        const interval = (new Date().getTime() - this.startTime) / 1000
        if (interval >= this.pollInterval) {
          this.bootstrap()
        } else {
          clearTimeout(this.setTimeoutId!)
          this.setTimeoutId = setTimeout(() => {
            this.bootstrap()
          }, (this.pollInterval - interval) * 1000)
        }
      }
    }
  }
}

export default Task
